﻿#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <iostream>
#include <string>
#include <vector>
#ifdef _WIN32
#include <openssl/applink.c>
#endif
#include <iomanip> // 用于std::hex和std::setw
#include <sstream> // 用于std::stringstream
// 函数：处理OpenSSL错误
void handleErrors() {
    ERR_print_errors_fp(stderr); // 打印错误到标准错误
    abort(); // 中止程序
}
std::string to_hex_string(const std::vector<unsigned char>& data) {
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (unsigned char c : data) {
        ss << std::setw(2) << static_cast<int>(c);
    }
    return ss.str();
}

// 函数：使用公钥加密数据
std::vector<unsigned char> encrypt(const std::string& data, const std::string& certFile) {
    // 打开证书文件
    FILE* fp = fopen(certFile.c_str(), "r");
    if (!fp) {
        throw std::runtime_error("Error opening certificate file"); // 文件打开失败，抛出异常
    }

    // 从文件中读取X509证书
    X509* cert = PEM_read_X509(fp, NULL, NULL, NULL);
    fclose(fp);
    if (!cert) {
        throw std::runtime_error("Error reading certificate"); // 证书读取失败，抛出异常
    }

    // 从证书中获取公钥
    EVP_PKEY* pubkey = X509_get_pubkey(cert);
    X509_free(cert); // 释放证书资源
    if (!pubkey) {
        throw std::runtime_error("Error getting public key from certificate"); // 获取公钥失败，抛出异常
    }

    // 创建公钥上下文
    EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pubkey, NULL);
    if (!ctx) handleErrors(); // 上下文创建失败，处理错误

    // 初始化公钥加密操作
    if (EVP_PKEY_encrypt_init(ctx) <= 0) handleErrors(); // 初始化失败，处理错误

    // 获取加密后数据的大小
    size_t outlen;
    if (EVP_PKEY_encrypt(ctx, NULL, &outlen, (unsigned char*)data.c_str(), data.length()) <= 0) handleErrors(); // 获取大小失败，处理错误

    // 根据获取的大小分配输出缓冲区
    std::vector<unsigned char> out(outlen);
    // 使用公钥加密数据
    if (EVP_PKEY_encrypt(ctx, out.data(), &outlen, (unsigned char*)data.c_str(), data.length()) <= 0) handleErrors(); // 加密失败，处理错误

    // 使用公钥加密数据
    if (EVP_PKEY_encrypt(ctx, out.data(), &outlen, (unsigned char*)data.c_str(), data.length()) <= 0) handleErrors();

    // 打印加密后的数据
    std::string encrypted_hex = to_hex_string(out);
    std::cout << "Encrypted data (hex): " << encrypted_hex << std::endl;
    // 释放资源
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pubkey);

    return out; // 返回加密后的数据
}

// 函数：使用私钥解密数据
std::string decrypt(const std::vector<unsigned char>& encryptedData, const std::string& keyFile) {
    // 打开私钥文件
    FILE* fp = fopen(keyFile.c_str(), "r");
    if (!fp) {
        throw std::runtime_error("Error opening private key file"); // 文件打开失败，抛出异常
    }

    // 从文件中读取私钥
    EVP_PKEY* privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
    fclose(fp);
    if (!privkey) {
        throw std::runtime_error("Error reading private key"); // 私钥读取失败，抛出异常
    }

    // 创建私钥上下文
    EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(privkey, NULL);
    if (!ctx) handleErrors(); // 上下文创建失败，处理错误

    // 初始化私钥解密操作
    if (EVP_PKEY_decrypt_init(ctx) <= 0) handleErrors(); // 初始化失败，处理错误

    // 获取解密后数据的大小
    size_t outlen;
    if (EVP_PKEY_decrypt(ctx, NULL, &outlen, encryptedData.data(), encryptedData.size()) <= 0) handleErrors(); // 获取大小失败，处理错误

    // 根据获取的大小分配输出缓冲区
    std::vector<unsigned char> out(outlen);
    // 使用私钥解密数据
    if (EVP_PKEY_decrypt(ctx, out.data(), &outlen, encryptedData.data(), encryptedData.size()) <= 0) handleErrors(); // 解密失败，处理错误

    // 释放资源
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(privkey);

    // 转换输出数据为字符串并返回
    return std::string(out.begin(), out.end());
}

int main() {
    // 注册所有算法和加载错误字符串
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    // 待加密数据
    std::string data = "This is a test message.";
    // 证书和私钥文件路径
    std::string certFile = "server.crt";
    std::string keyFile = "server.key";

    try {
        // 加密数据
        std::vector<unsigned char> encryptedData = encrypt(data, certFile);
        // 解密数据
        std::string decryptedData = decrypt(encryptedData, keyFile);

        // 打印原始数据和解密后的数据
        std::cout << "Original  data: " << data << std::endl;
        std::cout << "Decrypted data: " << decryptedData << std::endl;
    }
    catch (const std::exception& e) {
        // 捕获并打印异常信息
        std::cerr << "Error: " << e.what() << std::endl;
    }

    // 清理OpenSSL资源
    EVP_cleanup();
    ERR_free_strings();

    return 0; // 正常退出
}
